package org.dding.core.system.service;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;

import org.dding.core.log.ILogger;
import org.dding.core.log.LoggerFactory;
import org.dding.core.manager.IModuleManager;
import org.dding.core.manager.IServiceManager;
import org.dding.core.service.IServerConfig;
import org.dding.core.system.handler.DataSourceConfiguration;
import org.dding.core.system.handler.DataSourceHadnler;
import org.dding.core.util.StandaloneXmlParser.DataSourceConfig;
import org.dding.core.util.StringUtils;
import org.dding.msc.exception.StartException;
import org.dding.msc.service.Service;
import org.dding.msc.service.ServiceContainer;
import org.dding.msc.service.ServiceController;
import org.dding.msc.service.ServiceInfoWarehouse;
import org.dding.msc.service.ServiceInfoWarehouse.ServiceInfo;
import org.dding.msc.service.ServiceName;
import org.dding.msc.service.StartContext;

@org.dding.core.annotation.Service(name = IServiceManager._SYSTEM_SERVICE
		+ "datasource")
public class LocalDataSourceService extends AbstractDataSourceService {

	private static ILogger logger = LoggerFactory
			.getLogger(LocalDataSourceService.class);
	private ServiceInfoWarehouse house = ServiceInfoWarehouse.getInstance();

	static Properties properties = new Properties();

	static {
		InputStream inputStream = LocalDataSourceService.class.getClassLoader()
				.getResourceAsStream("META-INF/system_service.conf");
		try {
			properties.load(inputStream);
		} catch (IOException e) {
			logger.warn(e);
		}
	}

	@Override
	public synchronized void start(StartContext startContext) throws StartException {
		ServiceContainer serviceContainer = startContext.getController()
				.getServiceContainer();
		ServiceController<?> serverConfig = serviceContainer
				.getService(ServiceName.of(IServiceManager._SYSTEM_SERVICE
						+ "server.config"));
		if (serverConfig != null) {
			IServerConfig config = (IServerConfig) serverConfig.getValue();
			for (DataSourceConfig dataSourceConfig : config
					.getDataSourceConfig()) {
				if (!dataSourceConfig.enable)
					continue;
				if (dataSourceConfig.name != null) {
					processDataBase(config, dataSourceConfig, serviceContainer);
				}
				if (dataSourceConfig.poolConfig != null) {
					processPoolDataSource(new DataSourceConfiguration(
							dataSourceConfig, config.getModuleManager()));
				}
			}
		}
	}

	private void processPoolDataSource(DataSourceConfiguration config) {
		ServiceLoader<DataSourceHadnler> loader = ServiceLoader
				.load(DataSourceHadnler.class);
		Iterator<DataSourceHadnler> it = loader.iterator();
		while (it.hasNext()) {
			DataSourceHadnler handler = it.next();
			addDataSource(config.dataSourceConfig,
					handler.createDataSource(config));
		}
	}

	private void processDataBase(IServerConfig config, DataSourceConfig dataSourceConfig, ServiceContainer serviceContainer) {

		String database = (String) properties.get(dataSourceConfig.name);
		if (!StringUtils.isEmpty(database)) {

			int start = database.indexOf("[");
			int end = database.indexOf("]");
			String moduleName = null;
			String[] services = null;

			if (start >= 0 && end >= 0 && start < end) {
				moduleName = database.substring(0, start);
				String service = database.substring(start + 1, end);
				services = service.split(",");
			}
			if (moduleName != null && !"".equals(moduleName)) {
				IModuleManager moduleManager = config.getModuleManager();
				try {
					moduleManager.loadModule(moduleName);
				} catch (Throwable e) {
					logger.warn(e, "load module " + database + " failure.");
				}
			}
			if (services != null) {
				for (String serviceClass : services) {
					Object service = null;
					try {
						service = Class.forName(serviceClass).newInstance();
					} catch (Exception e) {
						logger.warn(e, "init service " + serviceClass
								+ " failure.");
						continue;
					}
					if (service != null) {
						serviceContainer.addService(
								ServiceName.of(IServiceManager._SYSTEM_SERVICE
										+ "db.hsql"), (Service<?>) service)
								.install();
						ServiceInfo serviceInfo = house
								.get(IServiceManager._SYSTEM_SERVICE
										+ "datasource");
						String systemModule = IServiceManager._SYSTEM_SERVICE
								+ "system.module";
						if (serviceInfo != null)
							systemModule = serviceInfo.moduleName;
						house.registry(IServiceManager._SYSTEM_SERVICE
								+ "db.hsql", house.new ServiceInfo(
								Service.class, systemModule));
					}
				}
			}
		}
	}
}
